package test.logic.nfm;

import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;

import org.apache.log4j.ConsoleAppender;
import org.apache.log4j.Logger;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

import cfsmon.common.Event;
import cfsmon.common.Parameter;
import cfsmon.core.LogConfig;
import cfsmon.logic.nfm.INfm;
import cfsmon.logic.nfm.Nfm;
import cfsmon.logic.nfm.NfmOptimizer;
import cfsmon.logic.nfm.NfmState;

public class NfmOptimizer01 {

	private INfm nfm;
	
	@BeforeClass
	public static void classSetUp(){
		Logger.getRootLogger().removeAllAppenders();
		Logger.getRootLogger().addAppender(new ConsoleAppender(LogConfig.cfsmonLogConsoleLayout));
	}
	
	@Test
	public void testNull() {
		
		INfm nfm = NfmOptimizer.optimize(null);
		assertNull(nfm);
		
	}

	@Before
	public void setUp(){
		nfm = new Nfm();
	}
	
	@After
	public void tearDown(){
		nfm = null;
	}
	
	@Test
	public void testReachableSetReduction() {
		nfm.addInitialState(new NfmState("s0"));
		nfm.addFinalState(new NfmState("s1"));
		nfm.addState(new NfmState("s2"));
		nfm.addEvent(new Event("e0"));
		nfm.getStates().get("s0").putTransition(
				nfm.getEvents().get("e0"),
				nfm.getStates().get("s1"));
		
		INfm optNfm = NfmOptimizer.optimize(nfm);
		assertNotNull(optNfm);
		assertNull(nfm.getStates().get("s2"));
	}
	
	@Test
	public void testReachableSetReductionWithDefaults() {
		nfm.addInitialState(new NfmState("s0"));
		nfm.addFinalState(new NfmState("s1"));
		nfm.addState(new NfmState("s2"));
		nfm.addEvent(new Event("e0"));
		nfm.getStates().get("s0").putTransition(
				nfm.getEvents().get("e0"),
				nfm.getStates().get("s1"));
		nfm.getStates().get("s0").addDefaultTransition(nfm.getStates().get("s2"));
		INfm optNfm = NfmOptimizer.optimize(nfm);
		assertNotNull(optNfm);
		assertNull(optNfm.getStates().get("s2"));
	}
	
	@Test
	public void testReachableSetReductionWithDisjunctParams() {
		NfmState s0, s1, s2;
		Event e0, e1;
		s0 = new NfmState("s0");
		s1 = new NfmState("s1");
		s2 = new NfmState("s2");
		e0 = new Event("e0");
		e0.parameters.add(new Parameter("int", "i"));
		e1 = new Event("e1");
		
		s0.putTransition(e0, s1);
		s0.putTransition(e1, s1);
		s0.addDefaultTransition(s2);
		
		nfm.addInitialState(s0);
		nfm.addFinalState(s1);
		nfm.addFinalState(s2);
		nfm.addEvent(e0);
		nfm.addEvent(e1);
		
		INfm optNfm = NfmOptimizer.optimize(nfm);
		assertNotNull(optNfm);
		assertNull(optNfm.getStates().get("s2"));
	}
	
	@Test
	public void testRedundantTransitions() {
		NfmState s0, s1;
		Event e0;
		s0 = new NfmState("s0");
		s1 = new NfmState("s1");
		e0 = new Event("e0");
		
		s0.putTransition(e0, s1);
		s0.addDefaultTransition(s1);
		
		nfm.addInitialState(s0);
		nfm.addFinalState(s1);
		nfm.addEvent(e0);
		
		INfm optNfm = NfmOptimizer.optimize(nfm);
		assertNotNull(optNfm);
		NfmState s0opt = optNfm.getStates().get("s0");
		assertNotNull(s0opt);
		assertNull(s0opt.getTransitions().get(e0));
	}
	
}
